<?php

namespace support\Strategy\Generate;

use LogicException;

/**
 * 代码生成类
 */
class Make
{

    protected string $name = '';
    protected string $table_name = '';
    protected string $namespace = 'app';

    /**
     * 构造方法
     * @access public
     */
    public function __construct($name)
    {
        if (!$name) throw new LogicException('请输入表名');
        $this->table_name = $name;
        $this->name = $this->ucword($name);
    }

    protected function ucword($name)
    {
        $temp = str_replace('_', ' ', $name);
        $camelCase = ucwords($temp);
        return str_replace(' ', '', $camelCase);
    }

    protected function getNamespace(string $app): string
    {
        return $this->namespace . ($app ? '\\' . $app : '');
    }

    protected function getClassName(string $name): string
    {
        if (str_contains($name, '\\')) {
            return $name;
        }
        if (strpos($name, '@')) {
            [$app, $name] = explode('@', $name);
        } else {
            $app = '';
        }
        if (str_contains($name, '/')) {
            $name = str_replace('/', '\\', $name);
        }
        return $this->getNamespace($app) . '\\' . $name;
    }

    /**
     * 生成控制器内容
     * @param $config array 基础配置
     * @return array
     */
    public function createController(array $config): array
    {

        $fileName = $this->name . 'Controller.php';
        $namespace = $this->getClassName('admin/controller/' . $this->name);
        $pathname = str_replace('\\', '/', $this->getPathName($namespace . 'Controller'));
        $stub = file_get_contents(base_path('support/Strategy/Generate/Stubs/controller.stub'));
        $content = str_replace(['{%className%}', '{%author%}', '{%date%}', '{%note%}'], [
            $this->name,
            $config['author'] ?? '',
            $config['time'] ?? date('Y-m-d'),
            $config['note'] ?? ''
        ], $stub);
        return $this->createResult($fileName, $pathname, $content);
    }


    public function logicSearchTemplate($list)
    {
        $searchs = '';
        $search = <<<EOF
if (!empty(\$param['{%columnQuery%}'])) {
            \$where[] = ["{%column%}", '{%query%}', {%columnQueryStr%}];
          }
EOF;
        if (!$list) return $searchs;
        $dictDataList = getDict('query_type_enum');
        foreach ($list as $item) {

            if (empty($dictDataList[$item['query_type']])) continue;
            $str = "\$param['" . $item['column_query'] . "']";
            $query = $dictDataList[$item['query_type']];
            if ($item['query_type'] == 8) {
                $query = 'like';
                $str = "\"%{\$param['" . $item['column_query'] . "']}%\"";
            }
            if ($item['query_type'] == 7) {
                $str = "[\$param['" . $item['column_query'] . "']??'',[\$param['" . $item['column_query'] . "']??''";
            }


            $new_search = str_replace(['{%columnQuery%}', '{%column%}', '{%query%}', '{%columnQueryStr%}'], [$item['column_query'], $item['column'], $query, $str], $search);
            $searchs .= $new_search;
        }
        return $searchs;
    }

    /**
     * 生成Logic内容
     * @param $config array 基础配置
     * @param $search_config array 搜索配置
     * @return array
     */
    public function createLogic(array $config, array $search_config): array
    {

        $fileName = $this->name . 'Logic.php';
        $namespace = $this->getClassName('admin/logic/' . $this->name);
        $pathname = str_replace('\\', '/', $this->getPathName($namespace . 'Logic'));
        $stub = file_get_contents(base_path('support/Strategy/Generate/Stubs/logic.stub'));
        //获取配置
        $searchs = $this->logicSearchTemplate($search_config['list'] ?? []);
        $content = str_replace(['{%className%}', '{%author%}', '{%date%}', '{%note%}', '{%search%}'], [

            $this->name,
            $config['author'] ?? '',
            $config['time'] ?? date('Y-m-d'),
            $config['note'] ?? '',
            $searchs
        ], $stub);
        return $this->createResult($fileName, $pathname, $content);
    }

    /**
     * 生成service内容
     * @param $config array 基础配置
     * @return array
     */
    public function createService(array $config): array
    {
        $this->namespace = 'support';
        $fileName = $this->name . 'Service.php';
        $namespace = $this->getClassName('Service/' . $this->name);
        $pathname = str_replace('\\', '/', $this->getPathName($namespace . 'Service'));
        $stub = file_get_contents(base_path('support/Strategy/Generate/Stubs/service.stub'));
        $content = str_replace(['{%className%}', '{%author%}', '{%date%}', '{%note%}'], [
            $this->name,
            $config['author'] ?? '',
            $config['time'] ?? date('Y-m-d'),
            $config['note'] ?? '',
        ], $stub);
        return $this->createResult($fileName, $pathname, $content);
    }

    /**
     * 生成model内容
     * @param $config array 基础配置
     * @return array
     */
    public function createModel(array $config): array
    {
        $this->namespace = 'support';
        $fileName = $this->name . 'Model.php';
        $namespace = $this->getClassName('Model/' . $this->name);
        $pathname = str_replace('\\', '/', $this->getPathName($namespace . 'Model'));
        $stub = file_get_contents(base_path('support/Strategy/Generate/Stubs/model.stub'));
        $content = str_replace(['{%className%}', '{%author%}', '{%date%}', '{%note%}','{%tableName%}'], [
            $this->name,
            $config['author'] ?? '',
            $config['time'] ?? date('Y-m-d'),
            $config['note'] ?? '',
            $this->table_name
        ], $stub);
        return $this->createResult($fileName, $pathname, $content);
    }


    public function validateRuleTemplate($list)
    {
        $rules = $messages = $scenes = '';
        $rule = <<<EOF
'{%column%}' => 'require',
EOF;
        $message = <<<EOF
 '{%column%}.require' => '请输入{%message%}',
EOF;
        $scene = <<<EOF
 '{%name%}' => [{%value%}],
EOF;
        if (!$list) return ['rules' => '', 'messages' => '', 'scenes' => ''];
        $add = $edit = '';
        foreach ($list as $item) {
            if (!$item['is_required']) continue;
            $new_rule = "\r\n" . str_replace(['{%column%}'], [$item['column_name']], $rule);
            $rules .= $new_rule;
            $new_message = "\r\n" . str_replace(['{%column%}', '{%message%}'], [$item['column_name'], $item['title']], $message);
            $messages .= $new_message;
            if ($item['show_add']) {
                $add .= "'" . $item['column_name'] . "',";
            }
            if ($item['show_edit']) {
                $edit .= "'" . $item['column_name'] . "',";
            }
        }
        if ($add) {
            $new_scene = "\r\n" . str_replace(['{%name%}', '{%value%}'], ['add', $add], $scene);
            $scenes .= $new_scene;
        }
        if ($edit) {
            $new_scene = "\r\n" . str_replace(['{%name%}', '{%value%}'], ['edit', $edit], $scene);
            $scenes .= rtrim($new_scene, ',');
        }
        return ['rules' => $rules, 'messages' => $messages, 'scenes' => $scenes];
    }


    /**
     * 生成validate内容
     * @param $config array 基础配置
     * @param $edit_config array 编辑配置
     * @return array
     */
    public function createValidate(array $config, array $edit_config): array
    {
        $this->namespace = 'app';
        $fileName = $this->name . 'Validate.php';
        $namespace = $this->getClassName('admin/validate/' . $this->name);
        $pathname = str_replace('\\', '/', $this->getPathName($namespace . 'Validate'));
        $stub = file_get_contents(base_path('support/Strategy/Generate/Stubs/validate.stub'));
        $rules = $messages = $scenes = '';
        if (!empty($edit_config['form']['is_show']) && $edit_config['form']['is_show'] == 1) {

            $res = $this->validateRuleTemplate($edit_config['list']);
            $rules = $res['rules'];
            $messages = $res['messages'];
            $scenes = $res['scenes'];
        }
        $content = str_replace(['{%className%}', '{%author%}', '{%date%}', '{%note%}', '{%rule%}', '{%message%}', '{%scene%}'], [
            $this->name,
            $config['author'] ?? '',
            $config['time'] ?? date('Y-m-d'),
            $config['note'] ?? '',
            $rules,
            $messages,
            $scenes
        ], $stub);
        return $this->createResult($fileName, $pathname, $content);
    }


    public function createIndexVue(array $config)
    {
        $this->namespace = '';
        $fileName = 'index.vue';
        $pathname = str_replace('\\', '/', $this->getPathWebName("web/src/views/$this->name/" . $fileName));
        $stub = file_get_contents(base_path('support/Strategy/Generate/Stubs/web/index.stub'));
        $content = str_replace(['{%className%}', '{%author%}', '{%date%}', '{%note%}'], [
            $this->name,
            $config['author'] ?? '',
            $config['time'] ?? date('Y-m-d'),
            $config['note'] ?? '',
        ], $stub);
        return $this->createResult($fileName, $pathname, $content);

    }

    public function createTableConfig($base_config)
    {
        if (!$base_config) return ['table_columns' => ''];
        if (empty($base_config['list'])) return ['table_columns' => ''];
        $table_columns = '';
        $column = <<<EOF
 {%column%},\r
EOF;
        foreach ($base_config['list'] as $item) {
            if (!$item['is_show']) continue;
            $column_config = "{title:'{$item['title']}',dataIndex:'{$item['column_as']}',align:'center',ellipsis:true,tooltip:true";
            if ($item['width']) {
                $column_config .= ',width:' . ((int)$item['width']) . '}';
            } else {
                $column_config .= '}';
            }
            $new_column = str_replace(
                ['{%column%}'],
                [$column_config],
                $column);
            $table_columns .= $new_column;
        }
        return ['table_columns' => $table_columns];
    }

    public function createTableSearchConfig($search_config)
    {
        if (!$search_config) return ['searchs' => '', 'querys' => ''];
        if (empty($search_config['list'])) return ['searchs' => '', 'querys' => ''];
        $search_columns = $querys = '';
        $search = <<<EOF
{
    label: '{%label%}',
    field: '{%column%}',
    type: '{%form_component%}',
    {%props%}
    {%options%}
  },\r
EOF;
        $query = <<<EOF
 queryForm.{%name%}=undefined;\r
EOF;
        foreach ($search_config['list'] as $item) {
            $options = '';
            $props = '';
            if (!in_array($item['form_component'], ['range-picker'])) {
                $props = "props:{placeholder:'请输入" . $item['column_name'] . "'},";
            }
            if (!empty($item['dict_code'])) {
                $options = "options: " . json_encode(getDictLabel($item['dict_code']), JSON_UNESCAPED_UNICODE) . ",";
            }
            $new_search = str_replace(
                ['{%label%}', '{%props%}', '{%column%}', '{%form_component%}', '{%options%}'],
                [$item['column_name'], $props, $item['column_query'], $item['form_component'], $options],
                $search);
            $search_columns .= $new_search;
            $new_query = str_replace(['{%name%}'], [$item['column_query']], $query);
            $querys .= $new_query;
        }
        return ['searchs' => $search_columns, 'querys' => $querys];
    }


    public function createTableVue(array $config, array $base_config, array $search_config, array $del_config)
    {
        $this->namespace = '';
        $fileName = 'table.vue';
        $pathname = str_replace('\\', '/', $this->getPathWebName("web/src/views/$this->name/components/" . $fileName));
        $stub = file_get_contents(base_path('support/Strategy/Generate/Stubs/web/table.stub'));
        //获取列表展示
        $res = $this->createTableConfig($base_config);
        $auth_add = "sys:$this->name:add";
        $auth_delete = "sys:$this->name:delete";
        $auth_edit = "sys:$this->name:edit";
        $auth_status = "sys:$this->name:status";
        //判断是否开启批量删除
        $is_show_batch_del = 'true';
        if ((isset($del_config['form']['is_show']) && $del_config['form']['is_show'] != 1) || (isset($del_config['form']['delete_type']) && !in_array(2, $del_config['form']['delete_type']))) {
            $is_show_batch_del = 'false';
        }
        //判断是否开启单个删除
        $is_show_del = 'true';
        if ((isset($del_config['form']['is_show']) && $del_config['form']['is_show'] != 1) || (isset($del_config['form']['delete_type']) && !in_array(1, $del_config['form']['delete_type']))) {
            $is_show_del = 'false';
        }
        //获取列表搜索
        $is_show_search = 'true';
        $res2 = $this->createTableSearchConfig($search_config);
        $searchs = $res2['searchs'] ?? '';
        if (!$searchs) {
            $is_show_search = 'false';
        }
        $content = str_replace(['{%className%}', '{%author%}', '{%date%}', '{%note%}', '{%table_column%}', '{%auth_add%}', '{%auth_del%}', '{%auth_edit%}', '{%auth_status%}', '{%is_show_batch_del%}', '{%is_show_del%}', '{%is_show_search%}', '{%search%}', ' {%querys%}'], [
            $this->name,
            $config['author'] ?? '',
            $config['time'] ?? date('Y-m-d'),
            $config['note'] ?? '',
            $res['table_columns'],
            $auth_add,
            $auth_delete,
            $auth_edit,
            $auth_status,
            $is_show_batch_del,
            $is_show_del,
            $is_show_search,
            $searchs,
            $res2['querys']
        ], $stub);
        return $this->createResult($fileName, $pathname, $content);

    }

    public function createFormColumns($edit_config): array
    {
        $columns = $updates = '';
        $update = <<<EOF
 {%name%}: {%column_default%},\r
EOF;
        $column = <<<EOF
{
    label: '{%label%}',
    field: '{%column%}',
    type: '{%form_component%}',
    hide:(form)=>{
      if(!form.id){
        return  {%show_add%}
      }else{
        return  {%show_edit%}
      }
    },
    props: {
      placeholder: '请输入{%name%}',
    },
    {%options%}
    {%rules%}
  },\r
EOF;
        if (!$edit_config) return ['updates' => $updates, 'columns' => $columns];
        if (empty($edit_config['form']['is_show']) || $edit_config['form']['is_show'] != 1) return ['updates' => $updates, 'columns' => $columns];
        if (empty($edit_config['list'])) return ['updates' => $updates, 'columns' => $columns];
        foreach ($edit_config['list'] as $item) {

            $column_default = "''";
            if (str_contains(strtolower($item['data_type']), 'int')) {
                if (is_null($item['column_default'])) {
                    $column_default = 0;
                } else {
                    $column_default = $item['column_default'];
                }
            }
            $new_update = str_replace(['{%name%}', '{%column_default%}'], [$item['column_name'], $column_default], $update);
            $updates .= $new_update;
            if (!$item['show_add'] && !$item['show_edit']) continue;
            $rules = '';
            $name = $item['title'];
            if ($item['is_required']) {
                $rules = "rules: [{ required: true, message: '请输入{$name}' }],";
            }
            $options = '';
            if (!empty($item['dict_code'])) {
                $options = "options: " . json_encode(getDictLabel($item['dict_code']), JSON_UNESCAPED_UNICODE) . ",";
            }

            $show_add = 'false';
            if ($item['show_add'] === false) {
                $show_add = 'true';
            }
            $show_edit = 'false';
            if ($item['show_edit'] === false) {
                $show_edit = 'true';
            }
            $new_column = str_replace(
                ['{%label%}', '{%rules%}', '{%name%}', '{%column%}', '{%form_component%}', '{%options%}', '{%show_add%}', '{%show_edit%}'],
                [$item['column_comment'], $rules, $name, $item['column_name'], $item['form_component'], $options, $show_add, $show_edit],
                $column);
            $columns .= $new_column;
        }
        return ['updates' => $updates, 'columns' => $columns];
    }

    public function createFromVue(array $config, array $edit_config)
    {
        $this->namespace = '';
        $fileName = 'from.vue';
        $pathname = str_replace('\\', '/', $this->getPathWebName("web/src/views/$this->name/components/" . $fileName));
        $stub = file_get_contents(base_path('support/Strategy/Generate/Stubs/web/from.stub'));
        $res = $this->createFormColumns($edit_config);
        $content = str_replace(['{%className%}', '{%author%}', '{%date%}', '{%note%}', '{%openWidth%}', '{%openType%}', ' {%columns%}', '{%updates%}'], [
            $this->name,
            $config['author'] ?? '',
            $config['time'] ?? date('Y-m-d'),
            $config['note'] ?? '',
            (int)($edit_config['form']['open_width'] ?? 500),
            $edit_config['form']['open_type'] ?? 'modal',
            $res['columns'],
            $res['updates']
        ], $stub);
        return $this->createResult($fileName, $pathname, $content);

    }

    public function apiTsSearchTemplate($list)
    {
        $searchs = '';
        $search = <<<EOF
 {%name%}?: any;\r
EOF;
        if (!$list) return $searchs;
        foreach ($list as $item) {
            $new_search = str_replace(['{%name%}',], [$item['column_query']], $search);
            $searchs .= $new_search;
        }
        return $searchs;
    }

    public function apiTsQueryTemplate($list)
    {
        $querys = '';
        $query = <<<EOF
 {%name%}?: any;\r
EOF;
        if (!$list) return $querys;
        foreach ($list as $item) {
            if (!$item['is_show']) continue;
            $new_query = str_replace(['{%name%}',], [$item['column_as']], $query);
            $querys .= $new_query;
        }
        return $querys;
    }

    public function apiTsSaveTemplate($config)
    {
        $updates = '';
        $update = <<<EOF
 {%name%}?: any;\r
EOF;
        if (!$config) return $updates;
        if (empty($config['form']['is_show']) || $config['form']['is_show'] != 1) return $updates;
        if (empty($config['list'])) return $updates;
        foreach ($config['list'] as $item) {
            $new_update = str_replace(['{%name%}',], [$item['column_name']], $update);
            $updates .= $new_update;
        }
        return $updates;
    }


    public function createApiTs(array $config, array $search_config, array $base_config, array $edit_config)
    {
        $this->namespace = '';
        $fileName = $this->name . '.ts';
        $pathname = str_replace('\\', '/', $this->getPathWebName("web/src/api/" . $fileName));
        $stub = file_get_contents(base_path('support/Strategy/Generate/Stubs/web/api.stub'));
        //生成搜索请求体
        $searchs = $this->apiTsSearchTemplate($search_config['list'] ?? '');
        //生成请求返回体
        $queryResponse = $this->apiTsQueryTemplate($base_config['list']);
        //生成编辑请求体
        $updateRequest = $this->apiTsSaveTemplate($edit_config);
        $content = str_replace(['{%name%}', '{%author%}', '{%date%}', '{%note%}', '{%searchs%}', '{%queryResponse%}', '{%updateRequest%}'], [
            lcfirst($this->name),
            $config['author'] ?? '',
            $config['time'] ?? date('Y-m-d'),
            $config['note'] ?? '',
            $searchs,
            $queryResponse,
            $updateRequest
        ], $stub);
        return $this->createResult($fileName, $pathname, $content);

    }

    /**
     * 创建返回参数
     * @param $fileName string 文件名称
     * @param $pathname string 文件地址
     * @param $content  string 文件内容
     * @return array
     */
    protected function createResult($fileName, $pathname, $content): array
    {
        $result['file_name'] = $fileName;
        $result['path'] = str_replace('/' . $fileName, '', $pathname);
        $result['content'] = $content;
        return $result;
    }

    protected function getPathName(string $name): string
    {
        if(defined('DS')){
            $ds=DS;
        }else{
            $ds=DIRECTORY_SEPARATOR;
        }
        return 'bhadmin' . $ds . ltrim($name . '.php');
    }

    protected function getPathWebName(string $name): string
    {
        if(defined('DS')){
            $ds=DS;
        }else{
            $ds=DIRECTORY_SEPARATOR;
        }
        return 'bhadmin' . $ds . ltrim($name);
    }


}